using System;
using System.Collections.Generic;
using System.IO;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;

namespace Nyanimals
{
    public enum MeshTypes { Static, Skeletal};
	public class CMesh
	{
		protected string name;
		protected VertexBuffer vertexBuffer;
		protected List<int> Textures; // indices from texture manager
		protected bool loaded;
		
		// mesh attributes
		protected int numVerts;
		protected int numTris;
		protected int numIndices;
		protected float UV_X, UV_Y;
		
		protected float[] pos;
		protected float[] norm;
		protected float[] tan;
		protected float[] UV;
		protected ushort[] indices;
        
        protected VertexFormat vertFormat;
		
		// properties
		public string Name 
		{
			get {return name;}
			set { name = value;}
		}
		public VertexBuffer VertBuffer
		{
			get { return vertexBuffer;}
		}
		public bool Loaded
		{
			get { return loaded;}
		}
		public int NumVerts
		{
			get { return numVerts;}
		}
		public int NumTris
		{
			get { return numTris;}
		}
		public int NumIndices
		{
			get { return numIndices;}
		}
		public float Scroll_X
		{
			get { return UV_X;}
		}
		public float Scroll_Y
		{
			get { return UV_Y;}
		}
        
        
        public float[] Positions
        {
            get{ return pos;}
        }
        public float[] Normals
        {
            get{ return norm;}
        }
        public float[] Tangents
        {
            get{ return tan;}
        }
        public float[] UVs
        {
            get{ return UV;}
        }
        public ushort[] Indices
        {
            get{ return indices;}
        }
        
		
		public CMesh ()
		{
			loaded = false;
		}
		public List<int> TextureList
		{
			get { return Textures;}
		}
        
        public virtual MeshTypes Type
        {
            get { return MeshTypes.Static;} 
        }
		
		public virtual void Load(string szFileName, BinaryReader read)
		{
			// dont continue if we are already loaded
			if(loaded == true)
			{
				return;
			}
            
            name = new string(szFileName.ToCharArray());
            
			// read in the count of stuff
			numVerts = read.ReadInt32();
			numTris = read.ReadInt32();
			numIndices = numTris * 3;
						
			// read in all the texture names
			int numTextures = read.ReadInt32();		
			Textures = new List<int>(numTextures);
			
			for(int texCount = 0; texCount < numTextures; ++texCount)
			{
				int textureLength = read.ReadInt32();
				string textureName = new string(read.ReadChars(textureLength));
				
				// add the texture
				Textures.Add(CTextureManager.Instance.LoadTexture(textureName));
			}
					
			// read in the UV scrolling data
			UV_X = read.ReadSingle();
			UV_Y = read.ReadSingle();		
		
			
			// build contiguous vert layouts
			pos = new float[numVerts * 3];
			norm = new float[numVerts * 3];
			tan = new float[numVerts * 3];
			UV = new float[numVerts * 2];
			indices = new ushort[numTris * 3];
			
			// read in all the verts
			int vertPos = 0;
			int UVPos = 0;
			for(int vertCount = 0; vertCount < numVerts; ++vertCount)
			{
				pos[vertPos + 0] = read.ReadSingle();
				pos[vertPos + 1] = read.ReadSingle();
				pos[vertPos + 2] = -read.ReadSingle();
				
				norm[vertPos + 0] = read.ReadSingle();
				norm[vertPos + 1] = read.ReadSingle();
				norm[vertPos + 2] = -read.ReadSingle();
				
				tan[vertPos + 0] = read.ReadSingle();
				tan[vertPos + 1] = read.ReadSingle();
				tan[vertPos + 2] = -read.ReadSingle();
				
				UV[UVPos + 0] = read.ReadSingle();
				UV[UVPos + 1] = read.ReadSingle();
				
				vertPos += 3;
				UVPos += 2;
			}
		
				// read in the triangle data
			for(int indexCount = 0; indexCount < numIndices; indexCount += 3)
			{
				// load with reversed winding order
				indices[indexCount + 0] = (ushort)read.ReadInt32();
				indices[indexCount + 1] = (ushort)read.ReadInt32();
				indices[indexCount + 2] = (ushort)read.ReadInt32();
			}
			loaded = true;
			
            // fill the bufferse
            ToGPU();
					
		}
        
        private void ToGPU()
        {
             VertexFormat[] vf = {VertexFormat.Float3, VertexFormat.Float2};
             vertexBuffer = new VertexBuffer(numVerts, numIndices, vf);
             vertexBuffer.SetVertices(0, pos);
             vertexBuffer.SetVertices(1, UV);
             // vertexBuffer.SetVertices(1, norm);
             // vertexBuffer.SetVertices(2, tan);
             // vertexBuffer.SetVertices(3, UV);
             vertexBuffer.SetIndices(indices);   
        }
        
        public void MakeBox(float width, float height, float depth, int tex = 0)
        {
            if(loaded)
            {
                return;
            }
            name = "box: " + width.ToString() + "x" + height.ToString() + "x" + depth.ToString();
            numVerts = 8;
            numTris = 12;
            numIndices = 36;
            UV_X = 0;
            UV_Y = 0;
            
            // give the first texture index
            // TODO: make sure index 0 is an empty texture
            Textures = new List<int>(1);
            Textures.Add(2);
            
            // the counts
            int vertCount = numVerts * 3;
            int uvCount = numVerts * 2;
            
            pos = new float[vertCount];
            norm = new float[vertCount];
            tan = new float[vertCount];
            UV = new float[uvCount];
            indices = new ushort[numIndices];
            
            // half all the dimentions
            width *= 0.5f;
            height *= 0.5f;
            depth *= 0.5f;
            
            // the positions
            int p = 0;
            pos[p++] =  width;  /**/    pos[p++] =  height;   /**/    pos[p++] =  depth; // (0) + + + 
            pos[p++] =  width;  /**/    pos[p++] = -height;   /**/    pos[p++] =  depth; // (1) + - + 
            pos[p++] =  width;  /**/    pos[p++] = -height;   /**/    pos[p++] = -depth; // (2) + - - 
            pos[p++] =  width;  /**/    pos[p++] =  height;   /**/    pos[p++] = -depth; // (3) + + -         
            pos[p++] = -width;  /**/    pos[p++] =  height;   /**/    pos[p++] =  depth; // (4) - + + 
            pos[p++] = -width;  /**/    pos[p++] =  height;   /**/    pos[p++] = -depth; // (5) - + - 
            pos[p++] = -width;  /**/    pos[p++] = -height;   /**/    pos[p++] = -depth; // (6) - - - 
            pos[p++] = -width;  /**/    pos[p++] = -height;   /**/    pos[p++] =  depth; // (7) - - + 
            
            // the UVs
            p = 0;
            UV[p++] = 0;    UV[p++] = 0;
            UV[p++] = 0;    UV[p++] = 1;
            UV[p++] = 1;    UV[p++] = 1;
            UV[p++] = 1;    UV[p++] = 0;
            UV[p++] = 0;    UV[p++] = 1;
            UV[p++] = 1;    UV[p++] = 1;
            UV[p++] = 1;    UV[p++] = 0;
            UV[p++] = 0;    UV[p++] = 0;
            
            // the indices
            p = 0;
            
            indices[p++] = 0;   indices[p++] = 1;   indices[p++] = 2; // left
            indices[p++] = 0;   indices[p++] = 2;   indices[p++] = 3;
            
            indices[p++] = 3;   indices[p++] = 2;   indices[p++] = 6; // front    
            indices[p++] = 3;   indices[p++] = 6;   indices[p++] = 5;
            
            indices[p++] = 4;   indices[p++] = 5;   indices[p++] = 6; // right
            indices[p++] = 4;   indices[p++] = 6;   indices[p++] = 7;       
            
            indices[p++] = 0;   indices[p++] = 4;   indices[p++] = 7; // back
            indices[p++] = 0;   indices[p++] = 7;   indices[p++] = 1; 
            
            indices[p++] = 3;   indices[p++] = 4;   indices[p++] = 0; // top           
            indices[p++] = 3;   indices[p++] = 5;   indices[p++] = 4;
            
            indices[p++] = 2;   indices[p++] = 7;   indices[p++] = 6; // bottom
            indices[p++] = 2;   indices[p++] = 1;   indices[p++] = 7;
            
            
            // fill the buffers
            ToGPU();
            
            loaded = true;
        }
	}
		
}







